home *** CD-ROM | disk | FTP | other *** search
/ CD Actual Thematic 7: Programming / CDAT7.iso / Share / Codigo / hh / rsource.exe / Heretic Source / P_MAP.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-02-13  |  37.8 KB  |  1,639 lines

  1. // P_map.c
  2.  
  3. #include "DoomDef.h"
  4. #include "P_local.h"
  5. #include "soundst.h"
  6.  
  7. /*
  8. ===============================================================================
  9.  
  10. NOTES:
  11.  
  12.  
  13. ===============================================================================
  14. */
  15.  
  16. /*
  17. ===============================================================================
  18.  
  19. mobj_t NOTES
  20.  
  21. mobj_ts are used to tell the refresh where to draw an image, tell the world simulation when objects are contacted, and tell the sound driver how to position a sound.
  22.  
  23. The refresh uses the next and prev links to follow lists of things in sectors as they are being drawn.  The sprite, frame, and angle elements determine which patch_t is used to draw the sprite if it is visible.  The sprite and frame values are allmost allways set from state_t structures.  The statescr.exe utility generates the states.h and states.c files that contain the sprite/frame numbers from the statescr.txt source file.  The xyz origin point represents a point at the bottom middle of the sprite (between the feet of a biped).  This is the default origin position for patch_ts grabbed with lumpy.exe.  A walking creature will have its z equal to the floor it is standing on.
  24.  
  25. The sound code uses the x,y, and subsector fields to do stereo positioning of any sound effited by the mobj_t.
  26.  
  27. The play simulation uses the blocklinks, x,y,z, radius, height to determine when mobj_ts are touching each other, touching lines in the map, or hit by trace lines (gunshots, lines of sight, etc). The mobj_t->flags element has various bit flags used by the simulation.
  28.  
  29.  
  30. Every mobj_t is linked into a single sector based on it's origin coordinates.
  31. The subsector_t is found with R_PointInSubsector(x,y), and the sector_t can be found with subsector->sector.  The sector links are only used by the rendering code,  the play simulation does not care about them at all.
  32.  
  33. Any mobj_t that needs to be acted upon be something else in the play world (block movement, be shot, etc) will also need to be linked into the blockmap.  If the thing has the MF_NOBLOCK flag set, it will not use the block links. It can still interact with other things, but only as the instigator (missiles will run into other things, but nothing can run into a missile).   Each block in the grid is 128*128 units, and knows about every line_t that it contains a piece of, and every interactable mobj_t that has it's origin contained.  
  34.  
  35. A valid mobj_t is a mobj_t that has the proper subsector_t filled in for it's xy coordinates and is linked into the subsector's sector or has the MF_NOSECTOR flag set (the subsector_t needs to be valid even if MF_NOSECTOR is set), and is linked into a blockmap block or has the MF_NOBLOCKMAP flag set.  Links should only be modified by the P_[Un]SetThingPosition () functions.  Do not change the MF_NO? flags while a thing is valid.
  36.  
  37.  
  38. ===============================================================================
  39. */
  40.  
  41. fixed_t        tmbbox[4];
  42. mobj_t        *tmthing;
  43. int            tmflags;
  44. fixed_t        tmx, tmy;
  45.  
  46. boolean        floatok;                // if true, move would be ok if
  47.                                     // within tmfloorz - tmceilingz
  48.  
  49. fixed_t        tmfloorz, tmceilingz, tmdropoffz;
  50.  
  51. // keep track of the line that lowers the ceiling, so missiles don't explode
  52. // against sky hack walls
  53. line_t        *ceilingline;
  54.  
  55. // keep track of special lines as they are hit, but don't process them
  56. // until the move is proven valid
  57. #define    MAXSPECIALCROSS        8
  58. line_t    *spechit[MAXSPECIALCROSS];
  59. int             numspechit;
  60.  
  61. mobj_t *onmobj; //generic global onmobj...used for landing on pods/players
  62.  
  63. /*
  64. ===============================================================================
  65.  
  66.                     TELEPORT MOVE
  67.  
  68. ===============================================================================
  69. */
  70.  
  71. /*
  72. ==================
  73. =
  74. = PIT_StompThing
  75. =
  76. ==================
  77. */
  78.  
  79. boolean PIT_StompThing (mobj_t *thing)
  80. {
  81.     fixed_t        blockdist;
  82.         
  83.     if (!(thing->flags & MF_SHOOTABLE) )
  84.         return true;
  85.         
  86.     blockdist = thing->radius + tmthing->radius;
  87.     if ( abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist )
  88.         return true;        // didn't hit it
  89.         
  90.     if (thing == tmthing)
  91.         return true;        // don't clip against self
  92.  
  93.     if(!(tmthing->flags2&MF2_TELESTOMP))
  94.     { // Not allowed to stomp things
  95.         return(false);
  96.     }
  97.         
  98.     P_DamageMobj (thing, tmthing, tmthing, 10000);
  99.     
  100.     return true;
  101. }
  102.  
  103.  
  104. /*
  105. ===================
  106. =
  107. = P_TeleportMove
  108. =
  109. ===================
  110. */
  111.  
  112. boolean P_TeleportMove (mobj_t *thing, fixed_t x, fixed_t y)
  113. {
  114.     int            xl,xh,yl,yh,bx,by;
  115.     subsector_t        *newsubsec;
  116.  
  117. //
  118. // kill anything occupying the position
  119. //
  120.  
  121.     tmthing = thing;
  122.     tmflags = thing->flags;
  123.     
  124.     tmx = x;
  125.     tmy = y;
  126.     
  127.     tmbbox[BOXTOP] = y + tmthing->radius;
  128.     tmbbox[BOXBOTTOM] = y - tmthing->radius;
  129.     tmbbox[BOXRIGHT] = x + tmthing->radius;
  130.     tmbbox[BOXLEFT] = x - tmthing->radius;
  131.  
  132.     newsubsec = R_PointInSubsector (x,y);
  133.     ceilingline = NULL;
  134.     
  135. //
  136. // the base floor / ceiling is from the subsector that contains the
  137. // point.  Any contacted lines the step closer together will adjust them
  138. //
  139.     tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
  140.     tmceilingz = newsubsec->sector->ceilingheight;
  141.             
  142.     validcount++;
  143.     numspechit = 0;
  144.  
  145. //
  146. // stomp on any things contacted
  147. //
  148.     xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
  149.     xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
  150.     yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
  151.     yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
  152.  
  153.     for (bx=xl ; bx<=xh ; bx++)
  154.         for (by=yl ; by<=yh ; by++)
  155.             if (!P_BlockThingsIterator(bx,by,PIT_StompThing))
  156.                 return false;
  157.     
  158. //
  159. // the move is ok, so link the thing into its new position
  160. //    
  161.     P_UnsetThingPosition (thing);
  162.  
  163.     thing->floorz = tmfloorz;
  164.     thing->ceilingz = tmceilingz;    
  165.     thing->x = x;
  166.     thing->y = y;
  167.  
  168.     P_SetThingPosition (thing);
  169.     
  170.     return true;
  171. }
  172.  
  173. /*
  174. ===============================================================================
  175.  
  176.                     MOVEMENT ITERATOR FUNCTIONS
  177.  
  178. ===============================================================================
  179. */
  180.  
  181. /*
  182. ==================
  183. =
  184. = PIT_CheckLine
  185. =
  186. = Adjusts tmfloorz and tmceilingz as lines are contacted
  187. ==================
  188. */
  189.  
  190. boolean PIT_CheckLine(line_t *ld)
  191. {
  192.     if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT]
  193.         ||    tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
  194.         ||    tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM]
  195.         ||    tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
  196.     {
  197.         return(true);
  198.     }
  199.     if(P_BoxOnLineSide(tmbbox, ld) != -1)
  200.     {
  201.         return(true);
  202.     }
  203.  
  204. // a line has been hit
  205. /*
  206. =
  207. = The moving thing's destination position will cross the given line.
  208. = If this should not be allowed, return false.
  209. = If the line is special, keep track of it to process later if the move
  210. =     is proven ok.  NOTE: specials are NOT sorted by order, so two special lines
  211. =     that are only 8 pixels apart could be crossed in either order.
  212. */
  213.  
  214.     if(!ld->backsector)
  215.     { // One sided line
  216.         if(tmthing->flags&MF_MISSILE)
  217.         { // Missiles can trigger impact specials
  218.             if(ld->special)
  219.             {
  220.                 spechit[numspechit] = ld;
  221.                 numspechit++;
  222.             }
  223.         }
  224.         return false;
  225.     }
  226.     if(!(tmthing->flags&MF_MISSILE))
  227.     {
  228.         if(ld->flags&ML_BLOCKING)
  229.         { // Explicitly blocking everything
  230.             return(false);
  231.         }
  232.         if(!tmthing->player && ld->flags&ML_BLOCKMONSTERS
  233.             && tmthing->type != MT_POD)
  234.         { // Block monsters only
  235.             return(false);
  236.         }
  237.     }
  238.     P_LineOpening(ld);        // set openrange, opentop, openbottom
  239.     // adjust floor / ceiling heights
  240.     if(opentop < tmceilingz)
  241.     {
  242.         tmceilingz = opentop;
  243.         ceilingline = ld;
  244.     }
  245.     if(openbottom > tmfloorz)
  246.     {
  247.         tmfloorz = openbottom;
  248.     }
  249.     if(lowfloor < tmdropoffz)
  250.     {
  251.         tmdropoffz = lowfloor;
  252.     }
  253.     if(ld->special)
  254.     { // Contacted a special line, add it to the list
  255.         spechit[numspechit] = ld;
  256.         numspechit++;
  257.     }
  258.     return(true);
  259. }
  260.  
  261. //---------------------------------------------------------------------------
  262. //
  263. // FUNC PIT_CheckThing
  264. //
  265. //---------------------------------------------------------------------------
  266.  
  267. boolean PIT_CheckThing(mobj_t *thing)
  268. {
  269.     fixed_t blockdist;
  270.     boolean solid;
  271.     int damage;
  272.  
  273.     if(!(thing->flags&(MF_SOLID|MF_SPECIAL|MF_SHOOTABLE)))
  274.     { // Can't hit thing
  275.         return(true);
  276.     }
  277.     blockdist = thing->radius+tmthing->radius;
  278.     if(abs(thing->x-tmx) >= blockdist || abs(thing->y-tmy) >= blockdist)
  279.     { // Didn't hit thing
  280.         return(true);
  281.     }
  282.     if(thing == tmthing)
  283.     { // Don't clip against self
  284.         return(true);
  285.     }
  286.     if(tmthing->flags2&MF2_PASSMOBJ)
  287.     { // check if a mobj passed over/under another object
  288.         if((tmthing->type == MT_IMP || tmthing->type == MT_WIZARD)
  289.             && (thing->type == MT_IMP || thing->type == MT_WIZARD))
  290.         { // don't let imps/wizards fly over other imps/wizards
  291.             return false;
  292.         }
  293.         if(tmthing->z > thing->z+thing->height 
  294.             && !(thing->flags&MF_SPECIAL))
  295.         {    
  296.             return(true);
  297.         }
  298.         else if(tmthing->z+tmthing->height < thing->z 
  299.             && !(thing->flags&MF_SPECIAL))
  300.         { // under thing
  301.             return(true);
  302.         }
  303.     }
  304.     // Check for skulls slamming into things
  305.     if(tmthing->flags&MF_SKULLFLY)
  306.     {
  307.         damage = ((P_Random()%8)+1)*tmthing->damage;
  308.         P_DamageMobj(thing, tmthing, tmthing, damage);
  309.         tmthing->flags &= ~MF_SKULLFLY;
  310.         tmthing->momx = tmthing->momy = tmthing->momz = 0;
  311.         P_SetMobjState(tmthing, tmthing->info->seestate);
  312.         return(false);
  313.     }
  314.     // Check for missile
  315.     if(tmthing->flags&MF_MISSILE)
  316.     {
  317.         // Check for passing through a ghost
  318.         if((thing->flags&MF_SHADOW) && (tmthing->flags2&MF2_THRUGHOST))
  319.         {
  320.             return(true);
  321.         }
  322.         // Check if it went over / under
  323.         if(tmthing->z > thing->z+thing->height)
  324.         { // Over thing
  325.             return(true);
  326.         }
  327.         if(tmthing->z+tmthing->height < thing->z)
  328.         { // Under thing
  329.             return(true);
  330.         }
  331.         if(tmthing->target && tmthing->target->type == thing->type)
  332.         { // Don't hit same species as originator
  333.             if(thing == tmthing->target)
  334.             { // Don't missile self
  335.                 return(true);
  336.             }
  337.             if(thing->type != MT_PLAYER)
  338.             { // Hit same species as originator, explode, no damage
  339.                 return(false);
  340.             }
  341.         }
  342.         if(!(thing->flags&MF_SHOOTABLE))
  343.         { // Didn't do any damage
  344.             return!(thing->flags&MF_SOLID);
  345.         }
  346.         if(tmthing->flags2&MF2_RIP)
  347.         {
  348.             if(!(thing->flags&MF_NOBLOOD))
  349.             { // Ok to spawn some blood
  350.                 P_RipperBlood(tmthing);
  351.             }
  352.             S_StartSound(tmthing, sfx_ripslop);
  353.             damage = ((P_Random()&3)+2)*tmthing->damage;
  354.             P_DamageMobj(thing, tmthing, tmthing->target, damage);
  355.             if(thing->flags2&MF2_PUSHABLE
  356.                 && !(tmthing->flags2&MF2_CANNOTPUSH))
  357.             { // Push thing
  358.                 thing->momx += tmthing->momx>>2;
  359.                 thing->momy += tmthing->momy>>2;
  360.             }
  361.             numspechit = 0;
  362.             return(true);
  363.         }
  364.         // Do damage
  365.         damage = ((P_Random()%8)+1)*tmthing->damage;
  366.         if(damage)
  367.         {
  368.             if(!(thing->flags&MF_NOBLOOD) && P_Random() < 192)
  369.             {
  370.                 P_BloodSplatter(tmthing->x, tmthing->y, tmthing->z, thing);
  371.             }
  372.             P_DamageMobj(thing, tmthing, tmthing->target, damage);
  373.         }
  374.         return(false);
  375.     }
  376.     if(thing->flags2&MF2_PUSHABLE && !(tmthing->flags2&MF2_CANNOTPUSH))
  377.     { // Push thing
  378.         thing->momx += tmthing->momx>>2;
  379.         thing->momy += tmthing->momy>>2;
  380.     }
  381.     // Check for special thing
  382.     if(thing->flags&MF_SPECIAL)
  383.     {
  384.         solid = thing->flags&MF_SOLID;
  385.         if(tmflags&MF_PICKUP)
  386.         { // Can be picked up by tmthing
  387.             P_TouchSpecialThing(thing, tmthing); // Can remove thing
  388.         }
  389.         return(!solid);
  390.     }
  391.     return(!(thing->flags&MF_SOLID));
  392. }
  393.  
  394. //---------------------------------------------------------------------------
  395. //
  396. // PIT_CheckOnmobjZ
  397. //
  398. //---------------------------------------------------------------------------
  399.  
  400. boolean PIT_CheckOnmobjZ(mobj_t *thing)
  401. {
  402.     fixed_t blockdist;
  403.  
  404.     if(!(thing->flags&(MF_SOLID|MF_SPECIAL|MF_SHOOTABLE)))
  405.     { // Can't hit thing
  406.         return(true);
  407.     }
  408.     blockdist = thing->radius+tmthing->radius;
  409.     if(abs(thing->x-tmx) >= blockdist || abs(thing->y-tmy) >= blockdist)
  410.     { // Didn't hit thing
  411.         return(true);
  412.     }
  413.     if(thing == tmthing)
  414.     { // Don't clip against self
  415.         return(true);
  416.     }
  417.     if(tmthing->z > thing->z+thing->height)
  418.     {    
  419.         return(true);
  420.     }
  421.     else if(tmthing->z+tmthing->height < thing->z)
  422.     { // under thing
  423.         return(true);
  424.     }
  425.     if(thing->flags&MF_SOLID)
  426.     {
  427.         onmobj = thing;
  428.     }
  429.     return(!(thing->flags&MF_SOLID));
  430. }
  431.  
  432. /*
  433. ===============================================================================
  434.  
  435.                          MOVEMENT CLIPPING
  436.  
  437. ===============================================================================
  438. */
  439.  
  440. //----------------------------------------------------------------------------
  441. //
  442. // FUNC P_TestMobjLocation
  443. //
  444. // Returns true if the mobj is not blocked by anything at its current
  445. // location, otherwise returns false.
  446. //
  447. //----------------------------------------------------------------------------
  448.  
  449. boolean P_TestMobjLocation(mobj_t *mobj)
  450. {
  451.     int flags;
  452.  
  453.     flags = mobj->flags;
  454.     mobj->flags &= ~MF_PICKUP;
  455.     if(P_CheckPosition(mobj, mobj->x, mobj->y))
  456.     { // XY is ok, now check Z
  457.         mobj->flags = flags;
  458.         if((mobj->z < mobj->floorz)
  459.             || (mobj->z+mobj->height > mobj->ceilingz))
  460.         { // Bad Z
  461.             return(false);
  462.         }
  463.         return(true);
  464.     }
  465.     mobj->flags = flags;
  466.     return(false);
  467. }
  468.  
  469. /*
  470. ==================
  471. =
  472. = P_CheckPosition
  473. =
  474. = This is purely informative, nothing is modified (except things picked up)
  475.  
  476. in:
  477. a mobj_t (can be valid or invalid)
  478. a position to be checked (doesn't need to be related to the mobj_t->x,y)
  479.  
  480. during:
  481. special things are touched if MF_PICKUP
  482. early out on solid lines?
  483.  
  484. out:
  485. newsubsec
  486. floorz
  487. ceilingz
  488. tmdropoffz        the lowest point contacted (monsters won't move to a dropoff)
  489. speciallines[]
  490. numspeciallines
  491.  
  492. ==================
  493. */
  494.  
  495. boolean P_CheckPosition (mobj_t *thing, fixed_t x, fixed_t y)
  496. {
  497.     int            xl,xh,yl,yh,bx,by;
  498.     subsector_t        *newsubsec;
  499.  
  500.     tmthing = thing;
  501.     tmflags = thing->flags;
  502.     
  503.     tmx = x;
  504.     tmy = y;
  505.     
  506.     tmbbox[BOXTOP] = y + tmthing->radius;
  507.     tmbbox[BOXBOTTOM] = y - tmthing->radius;
  508.     tmbbox[BOXRIGHT] = x + tmthing->radius;
  509.     tmbbox[BOXLEFT] = x - tmthing->radius;
  510.  
  511.     newsubsec = R_PointInSubsector (x,y);
  512.     ceilingline = NULL;
  513.     
  514. //
  515. // the base floor / ceiling is from the subsector that contains the
  516. // point.  Any contacted lines the step closer together will adjust them
  517. //
  518.     tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
  519.     tmceilingz = newsubsec->sector->ceilingheight;
  520.             
  521.     validcount++;
  522.     numspechit = 0;
  523.  
  524.     if ( tmflags & MF_NOCLIP )
  525.         return true;
  526.  
  527. //
  528. // check things first, possibly picking things up
  529. // the bounding box is extended by MAXRADIUS because mobj_ts are grouped
  530. // into mapblocks based on their origin point, and can overlap into adjacent
  531. // blocks by up to MAXRADIUS units
  532. //
  533.     xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
  534.     xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
  535.     yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
  536.     yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
  537.  
  538.     for (bx=xl ; bx<=xh ; bx++)
  539.         for (by=yl ; by<=yh ; by++)
  540.             if (!P_BlockThingsIterator(bx,by,PIT_CheckThing))
  541.                 return false;
  542. //
  543. // check lines
  544. //
  545.     xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT;
  546.     xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT;
  547.     yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT;
  548.     yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT;
  549.  
  550.     for (bx=xl ; bx<=xh ; bx++)
  551.         for (by=yl ; by<=yh ; by++)
  552.             if (!P_BlockLinesIterator (bx,by,PIT_CheckLine))
  553.                 return false;
  554.  
  555.     return true;
  556. }
  557.  
  558. //=============================================================================
  559. //
  560. // P_CheckOnmobj(mobj_t *thing)
  561. //
  562. //         Checks if the new Z position is legal
  563. //=============================================================================
  564.  
  565. mobj_t *P_CheckOnmobj(mobj_t *thing)
  566. {
  567.     int            xl,xh,yl,yh,bx,by;
  568.     subsector_t        *newsubsec;
  569.     fixed_t x;
  570.     fixed_t y;
  571.     mobj_t oldmo;
  572.     
  573.     x = thing->x;
  574.     y = thing->y;
  575.     tmthing = thing;
  576.     tmflags = thing->flags;
  577.     oldmo = *thing; // save the old mobj before the fake zmovement
  578.     P_FakeZMovement(tmthing);
  579.         
  580.     tmx = x;
  581.     tmy = y;
  582.     
  583.     tmbbox[BOXTOP] = y + tmthing->radius;
  584.     tmbbox[BOXBOTTOM] = y - tmthing->radius;
  585.     tmbbox[BOXRIGHT] = x + tmthing->radius;
  586.     tmbbox[BOXLEFT] = x - tmthing->radius;
  587.  
  588.     newsubsec = R_PointInSubsector (x,y);
  589.     ceilingline = NULL;
  590.     
  591. //
  592. // the base floor / ceiling is from the subsector that contains the
  593. // point.  Any contacted lines the step closer together will adjust them
  594. //
  595.     tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
  596.     tmceilingz = newsubsec->sector->ceilingheight;
  597.             
  598.     validcount++;
  599.     numspechit = 0;
  600.  
  601.     if ( tmflags & MF_NOCLIP )
  602.         return NULL;
  603.  
  604. //
  605. // check things first, possibly picking things up
  606. // the bounding box is extended by MAXRADIUS because mobj_ts are grouped
  607. // into mapblocks based on their origin point, and can overlap into adjacent
  608. // blocks by up to MAXRADIUS units
  609. //
  610.     xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
  611.     xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
  612.     yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
  613.     yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
  614.  
  615.     for (bx=xl ; bx<=xh ; bx++)
  616.         for (by=yl ; by<=yh ; by++)
  617.             if (!P_BlockThingsIterator(bx,by,PIT_CheckOnmobjZ))
  618.             {
  619.                 *tmthing = oldmo;
  620.                 return onmobj;
  621.             }
  622.     *tmthing = oldmo;
  623.     return NULL;
  624. }
  625.  
  626. //=============================================================================
  627. //
  628. // P_FakeZMovement
  629. //
  630. //         Fake the zmovement so that we can check if a move is legal
  631. //=============================================================================
  632.  
  633. void P_FakeZMovement(mobj_t *mo)
  634. {
  635.     int dist;
  636.     int delta;
  637. //
  638. // adjust height
  639. //
  640.     mo->z += mo->momz;
  641.     if(mo->flags&MF_FLOAT && mo->target)
  642.     {    // float down towards target if too close
  643.         if(!(mo->flags&MF_SKULLFLY) && !(mo->flags&MF_INFLOAT))
  644.         {
  645.             dist = P_AproxDistance(mo->x-mo->target->x, mo->y-mo->target->y);
  646.             delta =( mo->target->z+(mo->height>>1))-mo->z;
  647.             if (delta < 0 && dist < -(delta*3))
  648.                 mo->z -= FLOATSPEED;
  649.             else if (delta > 0 && dist < (delta*3))
  650.                 mo->z += FLOATSPEED;            
  651.         }
  652.     }
  653.     if(mo->player && mo->flags2&MF2_FLY && !(mo->z <= mo->floorz)
  654.         && leveltime&2)
  655.     {
  656.         mo->z += finesine[(FINEANGLES/20*leveltime>>2)&FINEMASK];
  657.     }
  658.  
  659. //
  660. // clip movement
  661. //
  662.     if(mo->z <= mo->floorz)
  663.     { // Hit the floor
  664.         mo->z = mo->floorz;
  665.         if(mo->momz < 0)
  666.         {
  667.             mo->momz = 0;
  668.         }
  669.         if(mo->flags&MF_SKULLFLY)
  670.         { // The skull slammed into something
  671.             mo->momz = -mo->momz;
  672.         }
  673.         if(mo->info->crashstate && (mo->flags&MF_CORPSE))
  674.         {
  675.             return;
  676.         }
  677.     }
  678.     else if(mo->flags2&MF2_LOGRAV)
  679.     {
  680.         if(mo->momz == 0)
  681.             mo->momz = -(GRAVITY>>3)*2;
  682.         else
  683.             mo->momz -= GRAVITY>>3;
  684.     }
  685.     else if (! (mo->flags & MF_NOGRAVITY) )
  686.     {
  687.         if (mo->momz == 0)
  688.             mo->momz = -GRAVITY*2;
  689.         else
  690.             mo->momz -= GRAVITY;
  691.     }
  692.     
  693.     if (mo->z + mo->height > mo->ceilingz)
  694.     {    // hit the ceiling
  695.         if (mo->momz > 0)
  696.             mo->momz = 0;
  697.         mo->z = mo->ceilingz - mo->height;        
  698.         if (mo->flags & MF_SKULLFLY)
  699.         {    // the skull slammed into something
  700.             mo->momz = -mo->momz;
  701.         }
  702.     }
  703. }
  704.  
  705. //==========================================================================
  706. //
  707. // CheckMissileImpact
  708. //
  709. //==========================================================================
  710.  
  711. void CheckMissileImpact(mobj_t *mobj)
  712. {
  713.     int i;
  714.  
  715.     if(!numspechit || !(mobj->flags&MF_MISSILE) || !mobj->target)
  716.     {
  717.         return;
  718.     }
  719.     if(!mobj->target->player)
  720.     {
  721.         return;
  722.     }
  723.     for(i = numspechit-1; i >= 0; i--)
  724.     {
  725.         P_ShootSpecialLine(mobj->target, spechit[i]);
  726.     }
  727. }
  728.  
  729. /*
  730. ===================
  731. =
  732. = P_TryMove
  733. =
  734. = Attempt to move to a new position, crossing special lines unless MF_TELEPORT
  735. = is set
  736. =
  737. ===================
  738. */
  739.  
  740. boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y)
  741. {
  742.     fixed_t        oldx, oldy;
  743.     int            side, oldside;
  744.     line_t        *ld;
  745.  
  746.     floatok = false;
  747.     if(!P_CheckPosition(thing, x, y))
  748.     { // Solid wall or thing
  749.         CheckMissileImpact(thing);
  750.         return false;
  751.     }
  752.     if(!(thing->flags&MF_NOCLIP))
  753.     {
  754.         if(tmceilingz-tmfloorz < thing->height)
  755.         { // Doesn't fit
  756.             CheckMissileImpact(thing);
  757.             return false;
  758.         }
  759.         floatok = true;
  760.         if(!(thing->flags&MF_TELEPORT)
  761.             && tmceilingz-thing->z < thing->height
  762.             && !(thing->flags2&MF2_FLY))
  763.         { // mobj must lower itself to fit
  764.             CheckMissileImpact(thing);
  765.             return false;
  766.         }
  767.         if(thing->flags2&MF2_FLY)
  768.         {
  769.             if(thing->z+thing->height > tmceilingz)
  770.             {
  771.                 thing->momz = -8*FRACUNIT;
  772.                 return false;
  773.             }
  774.             else if(thing->z < tmfloorz && tmfloorz-tmdropoffz > 24*FRACUNIT)
  775.             {
  776.                 thing->momz = 8*FRACUNIT;
  777.                 return false;
  778.             }
  779.         }
  780.         if(!(thing->flags&MF_TELEPORT)
  781.             // The Minotaur floor fire (MT_MNTRFX2) can step up any amount
  782.             && thing->type != MT_MNTRFX2
  783.             && tmfloorz-thing->z > 24*FRACUNIT)
  784.         { // Too big a step up
  785.             CheckMissileImpact(thing);
  786.             return false;
  787.         }
  788.         if((thing->flags&MF_MISSILE) && tmfloorz > thing->z)
  789.         {
  790.             CheckMissileImpact(thing);
  791.         }
  792.         if(!(thing->flags&(MF_DROPOFF|MF_FLOAT))
  793.             && tmfloorz-tmdropoffz > 24*FRACUNIT)
  794.         { // Can't move over a dropoff
  795.             return false;
  796.         }
  797.     }
  798.  
  799. //
  800. // the move is ok, so link the thing into its new position
  801. //
  802.     P_UnsetThingPosition (thing);
  803.  
  804.     oldx = thing->x;
  805.     oldy = thing->y;
  806.     thing->floorz = tmfloorz;
  807.     thing->ceilingz = tmceilingz;    
  808.     thing->x = x;
  809.     thing->y = y;
  810.  
  811.     P_SetThingPosition (thing);
  812.     
  813.     if(thing->flags2&MF2_FOOTCLIP && P_GetThingFloorType(thing) != FLOOR_SOLID)
  814.     {
  815.         thing->flags2 |= MF2_FEETARECLIPPED;
  816.     }
  817.     else if(thing->flags2&MF2_FEETARECLIPPED)
  818.     {
  819.         thing->flags2 &= ~MF2_FEETARECLIPPED;
  820.     }
  821.         
  822. //
  823. // if any special lines were hit, do the effect
  824. //
  825.     if (! (thing->flags&(MF_TELEPORT|MF_NOCLIP)) )
  826.         while (numspechit--)
  827.         {
  828.         // see if the line was crossed
  829.             ld = spechit[numspechit];
  830.             side = P_PointOnLineSide (thing->x, thing->y, ld);
  831.             oldside = P_PointOnLineSide (oldx, oldy, ld);
  832.             if (side != oldside)
  833.             {
  834.                 if (ld->special)
  835.                     P_CrossSpecialLine (ld-lines, oldside, thing);
  836.             }
  837.         }
  838.  
  839.     return true;
  840. }
  841.  
  842. /*
  843. ==================
  844. =
  845. = P_ThingHeightClip
  846. =
  847. = Takes a valid thing and adjusts the thing->floorz, thing->ceilingz,
  848. = anf possibly thing->z
  849. =
  850. = This is called for all nearby monsters whenever a sector changes height
  851. =
  852. = If the thing doesn't fit, the z will be set to the lowest value and
  853. = false will be returned
  854. ==================
  855. */
  856.  
  857. boolean P_ThingHeightClip (mobj_t *thing)
  858. {
  859.     boolean        onfloor;
  860.     
  861.     onfloor = (thing->z == thing->floorz);
  862.     
  863.     P_CheckPosition (thing, thing->x, thing->y);    
  864.     // what about stranding a monster partially off an edge?
  865.     
  866.     thing->floorz = tmfloorz;
  867.     thing->ceilingz = tmceilingz;
  868.     
  869.     if (onfloor)
  870.     // walking monsters rise and fall with the floor
  871.         thing->z = thing->floorz;
  872.     else
  873.     {    // don't adjust a floating monster unless forced to
  874.         if (thing->z+thing->height > thing->ceilingz)
  875.             thing->z = thing->ceilingz - thing->height;
  876.     }
  877.     
  878.     if (thing->ceilingz - thing->floorz < thing->height)
  879.         return false;
  880.         
  881.     return true;
  882. }
  883.  
  884.  
  885. /*
  886. ==============================================================================
  887.  
  888.                             SLIDE MOVE
  889.  
  890. Allows the player to slide along any angled walls
  891.  
  892. ==============================================================================
  893. */
  894.  
  895. fixed_t        bestslidefrac, secondslidefrac;
  896. line_t        *bestslideline, *secondslideline;
  897. mobj_t        *slidemo;
  898.  
  899. fixed_t        tmxmove, tmymove;
  900.  
  901. /*
  902. ==================
  903. =
  904. = P_HitSlideLine
  905. =
  906. = Adjusts the xmove / ymove so that the next move will slide along the wall
  907. ==================
  908. */
  909.  
  910. void P_HitSlideLine (line_t *ld)
  911. {
  912.     int            side;
  913.     angle_t        lineangle, moveangle, deltaangle;
  914.     fixed_t        movelen, newlen;
  915.     
  916.     
  917.     if (ld->slopetype == ST_HORIZONTAL)
  918.     {
  919.         tmymove = 0;
  920.         return;
  921.     }
  922.     if (ld->slopetype == ST_VERTICAL)
  923.     {
  924.         tmxmove = 0;
  925.         return;
  926.     }
  927.     
  928.     side = P_PointOnLineSide (slidemo->x, slidemo->y, ld);
  929.     
  930.     lineangle = R_PointToAngle2 (0,0, ld->dx, ld->dy);
  931.     if (side == 1)
  932.         lineangle += ANG180;
  933.     moveangle = R_PointToAngle2 (0,0, tmxmove, tmymove);
  934.     deltaangle = moveangle-lineangle;
  935.     if (deltaangle > ANG180)
  936.         deltaangle += ANG180;
  937. //        I_Error ("SlideLine: ang>ANG180");
  938.  
  939.     lineangle >>= ANGLETOFINESHIFT;
  940.     deltaangle >>= ANGLETOFINESHIFT;
  941.     
  942.     movelen = P_AproxDistance (tmxmove, tmymove);
  943.     newlen = FixedMul (movelen, finecosine[deltaangle]);
  944.     tmxmove = FixedMul (newlen, finecosine[lineangle]);    
  945.     tmymove = FixedMul (newlen, finesine[lineangle]);    
  946. }
  947.  
  948. /*
  949. ==============
  950. =
  951. = PTR_SlideTraverse
  952. =
  953. ==============
  954. */
  955.  
  956. boolean        PTR_SlideTraverse (intercept_t *in)
  957. {
  958.     line_t    *li;
  959.     
  960.     if (!in->isaline)
  961.         I_Error ("PTR_SlideTraverse: not a line?");
  962.         
  963.     li = in->d.line;
  964.     if ( ! (li->flags & ML_TWOSIDED) )
  965.     {
  966.         if (P_PointOnLineSide (slidemo->x, slidemo->y, li))
  967.             return true;        // don't hit the back side
  968.         goto isblocking;
  969.     }
  970.  
  971.     P_LineOpening (li);            // set openrange, opentop, openbottom
  972.     if (openrange < slidemo->height)
  973.         goto isblocking;        // doesn't fit
  974.         
  975.     if (opentop - slidemo->z < slidemo->height)
  976.         goto isblocking;        // mobj is too high
  977.  
  978.     if (openbottom - slidemo->z > 24*FRACUNIT )
  979.         goto isblocking;        // too big a step up
  980.  
  981.     return true;        // this line doesn't block movement
  982.     
  983. // the line does block movement, see if it is closer than best so far
  984. isblocking:        
  985.     if (in->frac < bestslidefrac)
  986.     {
  987.         secondslidefrac = bestslidefrac;
  988.         secondslideline = bestslideline;
  989.         bestslidefrac = in->frac;
  990.         bestslideline = li;
  991.     }
  992.     
  993.     return false;    // stop
  994. }
  995.  
  996.  
  997. /*
  998. ==================
  999. =
  1000. = P_SlideMove
  1001. =
  1002. = The momx / momy move is bad, so try to slide along a wall
  1003. =
  1004. = Find the first line hit, move flush to it, and slide along it
  1005. =
  1006. = This is a kludgy mess.
  1007. ==================
  1008. */
  1009.  
  1010. void P_SlideMove (mobj_t *mo)
  1011. {
  1012.     fixed_t        leadx, leady;
  1013.     fixed_t        trailx, traily;
  1014.     fixed_t        newx, newy;
  1015.     int            hitcount;
  1016.         
  1017.     slidemo = mo;
  1018.     hitcount = 0;
  1019. retry:
  1020.     if (++hitcount == 3)
  1021.         goto stairstep;            // don't loop forever
  1022.             
  1023. //
  1024. // trace along the three leading corners
  1025. //
  1026.     if (mo->momx > 0)
  1027.     {
  1028.         leadx = mo->x + mo->radius;
  1029.         trailx = mo->x - mo->radius;
  1030.     }
  1031.     else
  1032.     {
  1033.         leadx = mo->x - mo->radius;
  1034.         trailx = mo->x + mo->radius;
  1035.     }
  1036.     
  1037.     if (mo->momy > 0)
  1038.     {
  1039.         leady = mo->y + mo->radius;
  1040.         traily = mo->y - mo->radius;
  1041.     }
  1042.     else
  1043.     {
  1044.         leady = mo->y - mo->radius;
  1045.         traily = mo->y + mo->radius;
  1046.     }
  1047.         
  1048.     bestslidefrac = FRACUNIT+1;
  1049.     
  1050.     P_PathTraverse ( leadx, leady, leadx+mo->momx, leady+mo->momy,
  1051.      PT_ADDLINES, PTR_SlideTraverse );
  1052.     P_PathTraverse ( trailx, leady, trailx+mo->momx, leady+mo->momy,
  1053.      PT_ADDLINES, PTR_SlideTraverse );
  1054.     P_PathTraverse ( leadx, traily, leadx+mo->momx, traily+mo->momy,
  1055.      PT_ADDLINES, PTR_SlideTraverse );
  1056.  
  1057. //
  1058. // move up to the wall
  1059. //
  1060.     if (bestslidefrac == FRACUNIT+1)
  1061.     {    // the move most have hit the middle, so stairstep
  1062. stairstep:
  1063.         if (!P_TryMove (mo, mo->x, mo->y + mo->momy))
  1064.             P_TryMove (mo, mo->x + mo->momx, mo->y);
  1065.         return;
  1066.     }
  1067.     
  1068.     bestslidefrac -= 0x800;    // fudge a bit to make sure it doesn't hit
  1069.     if (bestslidefrac > 0)
  1070.     {
  1071.         newx = FixedMul (mo->momx, bestslidefrac);
  1072.         newy = FixedMul (mo->momy, bestslidefrac);
  1073.         if (!P_TryMove (mo, mo->x+newx, mo->y+newy))
  1074.             goto stairstep;
  1075.     }
  1076.         
  1077. //
  1078. // now continue along the wall
  1079. //
  1080.     bestslidefrac = FRACUNIT-(bestslidefrac+0x800);    // remainder
  1081.     if (bestslidefrac > FRACUNIT)
  1082.         bestslidefrac = FRACUNIT;
  1083.     if (bestslidefrac <= 0)
  1084.         return;
  1085.         
  1086.     tmxmove = FixedMul (mo->momx, bestslidefrac);
  1087.     tmymove = FixedMul (mo->momy, bestslidefrac);
  1088.  
  1089.     P_HitSlideLine (bestslideline);                // clip the moves
  1090.  
  1091.     mo->momx = tmxmove;
  1092.     mo->momy = tmymove;
  1093.         
  1094.     if (!P_TryMove (mo, mo->x+tmxmove, mo->y+tmymove))
  1095.     {
  1096.         goto retry;
  1097.     }
  1098. }
  1099.  
  1100.  
  1101.  
  1102. /*
  1103. ==============================================================================
  1104.  
  1105.                             P_LineAttack
  1106.  
  1107. ==============================================================================
  1108. */
  1109.  
  1110.  
  1111. mobj_t        *linetarget;            // who got hit (or NULL)
  1112. mobj_t        *shootthing;
  1113. fixed_t        shootz;                    // height if not aiming up or down
  1114.                                     // ???: use slope for monsters?
  1115. int            la_damage;
  1116. fixed_t        attackrange;
  1117.  
  1118. fixed_t        aimslope;
  1119.  
  1120. extern    fixed_t        topslope, bottomslope;    // slopes to top and bottom of target
  1121.  
  1122. /*
  1123. ===============================================================================
  1124. =
  1125. = PTR_AimTraverse
  1126. =
  1127. = Sets linetaget and aimslope when a target is aimed at
  1128. ===============================================================================
  1129. */
  1130.  
  1131. boolean        PTR_AimTraverse (intercept_t *in)
  1132. {
  1133.     line_t        *li;
  1134.     mobj_t        *th;
  1135.     fixed_t        slope, thingtopslope, thingbottomslope;
  1136.     fixed_t        dist;
  1137.         
  1138.     if (in->isaline)
  1139.     {
  1140.         li = in->d.line;
  1141.         if ( !(li->flags & ML_TWOSIDED) )
  1142.             return false;        // stop
  1143. //
  1144. // crosses a two sided line
  1145. // a two sided line will restrict the possible target ranges
  1146.         P_LineOpening (li);
  1147.     
  1148.         if (openbottom >= opentop)
  1149.             return false;        // stop
  1150.     
  1151.         dist = FixedMul (attackrange, in->frac);
  1152.  
  1153.         if (li->frontsector->floorheight != li->backsector->floorheight)
  1154.         {
  1155.             slope = FixedDiv (openbottom - shootz , dist);
  1156.             if (slope > bottomslope)
  1157.                 bottomslope = slope;
  1158.         }
  1159.         
  1160.         if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
  1161.         {
  1162.             slope = FixedDiv (opentop - shootz , dist);
  1163.             if (slope < topslope)
  1164.                 topslope = slope;
  1165.         }
  1166.         
  1167.         if (topslope <= bottomslope)
  1168.             return false;        // stop
  1169.             
  1170.         return true;        // shot continues
  1171.     }
  1172.     
  1173. //
  1174. // shoot a thing
  1175. //
  1176.     th = in->d.thing;
  1177.     if (th == shootthing)
  1178.         return true;        // can't shoot self
  1179.     if (!(th->flags&MF_SHOOTABLE))
  1180.         return true;        // corpse or something
  1181.     if(th->type == MT_POD)
  1182.     { // Can't auto-aim at pods
  1183.         return(true);
  1184.     }
  1185.  
  1186. // check angles to see if the thing can be aimed at
  1187.  
  1188.     dist = FixedMul (attackrange, in->frac);
  1189.     thingtopslope = FixedDiv (th->z+th->height - shootz , dist);
  1190.     if (thingtopslope < bottomslope)
  1191.         return true;        // shot over the thing
  1192.     thingbottomslope = FixedDiv (th->z - shootz, dist);
  1193.     if (thingbottomslope > topslope)
  1194.         return true;        // shot under the thing
  1195.  
  1196. //
  1197. // this thing can be hit!
  1198. //
  1199.     if (thingtopslope > topslope)
  1200.         thingtopslope = topslope;
  1201.     if (thingbottomslope < bottomslope)
  1202.         thingbottomslope = bottomslope;
  1203.  
  1204.     aimslope = (thingtopslope+thingbottomslope)/2;
  1205.     linetarget = th;
  1206.  
  1207.     return false;            // don't go any farther
  1208. }
  1209.  
  1210.  
  1211. /*
  1212. ==============================================================================
  1213. =
  1214. = PTR_ShootTraverse
  1215. =
  1216. ==============================================================================
  1217. */
  1218.  
  1219. boolean        PTR_ShootTraverse (intercept_t *in)
  1220. {
  1221.     fixed_t        x,y,z;
  1222.     fixed_t        frac;
  1223.     line_t        *li;
  1224.     mobj_t        *th;
  1225.     fixed_t        slope;
  1226.     fixed_t        dist;
  1227.     fixed_t        thingtopslope, thingbottomslope;
  1228.     mobj_t *mo;
  1229.  
  1230.     if (in->isaline)
  1231.     {
  1232.         li = in->d.line;
  1233.         if (li->special)
  1234.             P_ShootSpecialLine (shootthing, li);
  1235.         if ( !(li->flags & ML_TWOSIDED) )
  1236.             goto hitline;
  1237.  
  1238. //
  1239. // crosses a two sided line
  1240. //
  1241.         P_LineOpening (li);
  1242.         
  1243.         dist = FixedMul (attackrange, in->frac);
  1244.  
  1245.         if (li->frontsector->floorheight != li->backsector->floorheight)
  1246.         {
  1247.             slope = FixedDiv (openbottom - shootz , dist);
  1248.             if (slope > aimslope)
  1249.                 goto hitline;
  1250.         }
  1251.         
  1252.         if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
  1253.         {
  1254.             slope = FixedDiv (opentop - shootz , dist);
  1255.             if (slope < aimslope)
  1256.                 goto hitline;
  1257.         }
  1258.             
  1259.         return true;        // shot continues
  1260. //
  1261. // hit line
  1262. //
  1263. hitline:
  1264.         // position a bit closer
  1265.         frac = in->frac - FixedDiv (4*FRACUNIT,attackrange);
  1266.         x = trace.x + FixedMul (trace.dx, frac);
  1267.         y = trace.y + FixedMul (trace.dy, frac);
  1268.         z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange));
  1269.  
  1270.         if (li->frontsector->ceilingpic == skyflatnum)
  1271.         {
  1272.             if (z > li->frontsector->ceilingheight)
  1273.                 return false;        // don't shoot the sky!
  1274.             if    (li->backsector && li->backsector->ceilingpic == skyflatnum)
  1275.                 return false;        // it's a sky hack wall
  1276.         }
  1277.                 
  1278.         P_SpawnPuff (x,y,z);
  1279.         return false;            // don't go any farther
  1280.     }
  1281.     
  1282. //
  1283. // shoot a thing
  1284. //
  1285.     th = in->d.thing;
  1286.     if (th == shootthing)
  1287.         return true;        // can't shoot self
  1288.     if (!(th->flags&MF_SHOOTABLE))
  1289.         return true;        // corpse or something
  1290.  
  1291. //
  1292. // check for physical attacks on a ghost
  1293. //
  1294.     if(th->flags&MF_SHADOW && shootthing->player->readyweapon == wp_staff)
  1295.     {
  1296.         return(true);
  1297.     }
  1298.  
  1299. // check angles to see if the thing can be aimed at
  1300.     dist = FixedMul (attackrange, in->frac);
  1301.     thingtopslope = FixedDiv (th->z+th->height - shootz , dist);
  1302.     if (thingtopslope < aimslope)
  1303.         return true;        // shot over the thing
  1304.     thingbottomslope = FixedDiv (th->z - shootz, dist);
  1305.     if (thingbottomslope > aimslope)
  1306.         return true;        // shot under the thing
  1307.  
  1308. //
  1309. // hit thing
  1310. //
  1311.     // position a bit closer
  1312.     frac = in->frac - FixedDiv (10*FRACUNIT,attackrange);
  1313.     x = trace.x + FixedMul(trace.dx, frac);
  1314.     y = trace.y + FixedMul(trace.dy, frac);
  1315.     z = shootz + FixedMul(aimslope, FixedMul(frac, attackrange));
  1316.     if(PuffType == MT_BLASTERPUFF1)
  1317.     { // Make blaster big puff
  1318.         mo = P_SpawnMobj(x, y, z, MT_BLASTERPUFF2);
  1319.         S_StartSound(mo, sfx_blshit);
  1320.     }
  1321.     else
  1322.     {
  1323.         P_SpawnPuff(x, y, z);
  1324.     }
  1325.     if(la_damage)
  1326.     {
  1327.         if(!(in->d.thing->flags&MF_NOBLOOD) && P_Random() < 192)
  1328.         {
  1329.             P_BloodSplatter(x, y, z, in->d.thing);
  1330.         }
  1331.         P_DamageMobj(th, shootthing, shootthing, la_damage);
  1332.     }
  1333.     return(false); // don't go any farther
  1334. }
  1335.  
  1336. /*
  1337. =================
  1338. =
  1339. = P_AimLineAttack
  1340. =
  1341. =================
  1342. */
  1343.  
  1344. fixed_t P_AimLineAttack (mobj_t *t1, angle_t angle, fixed_t distance)
  1345. {
  1346.     fixed_t        x2, y2;
  1347.     
  1348.     angle >>= ANGLETOFINESHIFT;
  1349.     shootthing = t1;
  1350.     x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
  1351.     y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
  1352.     shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
  1353.     topslope = 100*FRACUNIT/160;    // can't shoot outside view angles
  1354.     bottomslope = -100*FRACUNIT/160;
  1355.     attackrange = distance;
  1356.     linetarget = NULL;
  1357.     
  1358.     P_PathTraverse ( t1->x, t1->y, x2, y2
  1359.         , PT_ADDLINES|PT_ADDTHINGS, PTR_AimTraverse );
  1360.         
  1361.     if (linetarget)
  1362.         return aimslope;
  1363.     return 0;
  1364. }
  1365.  
  1366.  
  1367.  
  1368. /*
  1369. =================
  1370. =
  1371. = P_LineAttack
  1372. =
  1373. = if damage == 0, it is just a test trace that will leave linetarget set
  1374. =
  1375. =================
  1376. */
  1377.  
  1378. void P_LineAttack (mobj_t *t1, angle_t angle, fixed_t distance, fixed_t slope, int damage)
  1379. {
  1380.     fixed_t        x2, y2;
  1381.     
  1382.     angle >>= ANGLETOFINESHIFT;
  1383.     shootthing = t1;
  1384.     la_damage = damage;
  1385.     x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
  1386.     y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
  1387.     shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
  1388.     if(t1->flags2&MF2_FEETARECLIPPED)
  1389.     {
  1390.         shootz -= FOOTCLIPSIZE;
  1391.     }
  1392.     attackrange = distance;
  1393.     aimslope = slope;
  1394.         
  1395.     P_PathTraverse ( t1->x, t1->y, x2, y2
  1396.         , PT_ADDLINES|PT_ADDTHINGS, PTR_ShootTraverse );
  1397. }
  1398.  
  1399.  
  1400.  
  1401. /*
  1402. ==============================================================================
  1403.  
  1404.                             USE LINES
  1405.  
  1406. ==============================================================================
  1407. */
  1408.  
  1409. mobj_t        *usething;
  1410.  
  1411. boolean        PTR_UseTraverse (intercept_t *in)
  1412. {
  1413.     if (!in->d.line->special)
  1414.     {
  1415.         P_LineOpening (in->d.line);
  1416.         if (openrange <= 0)
  1417.         {
  1418.             //S_StartSound (usething, sfx_noway);
  1419.             return false;    // can't use through a wall
  1420.         }
  1421.         return true ;        // not a special line, but keep checking
  1422.     }
  1423.         
  1424.     if (P_PointOnLineSide (usething->x, usething->y, in->d.line) == 1)
  1425.         return false;        // don't use back sides
  1426.         
  1427.     P_UseSpecialLine (usething, in->d.line);
  1428.  
  1429.     return false;            // can't use for than one special line in a row
  1430. }
  1431.  
  1432.  
  1433. /*
  1434. ================
  1435. =
  1436. = P_UseLines
  1437. =
  1438. = Looks for special lines in front of the player to activate
  1439. ================ 
  1440. */
  1441.  
  1442. void P_UseLines (player_t *player)
  1443. {
  1444.     int            angle;
  1445.     fixed_t        x1, y1, x2, y2;
  1446.     
  1447.     usething = player->mo;
  1448.         
  1449.     angle = player->mo->angle >> ANGLETOFINESHIFT;
  1450.     x1 = player->mo->x;
  1451.     y1 = player->mo->y;
  1452.     x2 = x1 + (USERANGE>>FRACBITS)*finecosine[angle];
  1453.     y2 = y1 + (USERANGE>>FRACBITS)*finesine[angle];
  1454.     
  1455.     P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse );
  1456. }
  1457.  
  1458.  
  1459.  
  1460. /*
  1461. ==============================================================================
  1462.  
  1463.                             RADIUS ATTACK
  1464.  
  1465. ==============================================================================
  1466. */
  1467.  
  1468. mobj_t        *bombsource;
  1469. mobj_t        *bombspot;
  1470. int            bombdamage;
  1471.  
  1472. /*
  1473. =================
  1474. =
  1475. = PIT_RadiusAttack
  1476. =
  1477. = Source is the creature that casued the explosion at spot
  1478. =================
  1479. */
  1480.  
  1481. boolean PIT_RadiusAttack (mobj_t *thing)
  1482. {
  1483.     fixed_t dx, dy, dist;
  1484.  
  1485.     if(!(thing->flags&MF_SHOOTABLE))
  1486.     {
  1487.         return true;
  1488.     }
  1489.     if(thing->type == MT_MINOTAUR || thing->type == MT_SORCERER1
  1490.         || thing->type == MT_SORCERER2)
  1491.     { // Episode 2 and 3 bosses take no damage from PIT_RadiusAttack
  1492.         return(true);
  1493.     }
  1494.     dx = abs(thing->x - bombspot->x);
  1495.     dy = abs(thing->y - bombspot->y);
  1496.     dist = dx > dy ? dx : dy;
  1497.     dist = (dist - thing->radius) >> FRACBITS;
  1498.     if(dist < 0)
  1499.     {
  1500.         dist = 0;
  1501.     }
  1502.     if(dist >= bombdamage)
  1503.     { // Out of range
  1504.         return true;
  1505.     }
  1506.     if(P_CheckSight(thing, bombspot))
  1507.     { // OK to damage, target is in direct path
  1508.         P_DamageMobj(thing, bombspot, bombsource, bombdamage - dist);
  1509.     }
  1510.     return(true);
  1511. }
  1512.  
  1513. /*
  1514. =================
  1515. =
  1516. = P_RadiusAttack
  1517. =
  1518. = Source is the creature that casued the explosion at spot
  1519. =================
  1520. */
  1521.  
  1522. void P_RadiusAttack (mobj_t *spot, mobj_t *source, int damage)
  1523. {
  1524.     int            x,y, xl, xh, yl, yh;
  1525.     fixed_t        dist;
  1526.     
  1527.     dist = (damage+MAXRADIUS)<<FRACBITS;
  1528.     yh = (spot->y + dist - bmaporgy)>>MAPBLOCKSHIFT;
  1529.     yl = (spot->y - dist - bmaporgy)>>MAPBLOCKSHIFT;
  1530.     xh = (spot->x + dist - bmaporgx)>>MAPBLOCKSHIFT;
  1531.     xl = (spot->x - dist - bmaporgx)>>MAPBLOCKSHIFT;
  1532.     bombspot = spot;
  1533.     if(spot->type == MT_POD && spot->target)
  1534.     {
  1535.         bombsource = spot->target;
  1536.     }
  1537.     else
  1538.     {
  1539.         bombsource = source;
  1540.     }
  1541.     bombdamage = damage;
  1542.     for (y=yl ; y<=yh ; y++)
  1543.         for (x=xl ; x<=xh ; x++)
  1544.             P_BlockThingsIterator (x, y, PIT_RadiusAttack );
  1545. }
  1546.  
  1547.  
  1548. /*
  1549. ==============================================================================
  1550.  
  1551.                         SECTOR HEIGHT CHANGING
  1552.  
  1553. = After modifying a sectors floor or ceiling height, call this
  1554. = routine to adjust the positions of all things that touch the
  1555. = sector.
  1556. =
  1557. = If anything doesn't fit anymore, true will be returned.
  1558. = If crunch is true, they will take damage as they are being crushed
  1559. = If Crunch is false, you should set the sector height back the way it
  1560. = was and call P_ChangeSector again to undo the changes
  1561. ==============================================================================
  1562. */
  1563.  
  1564. boolean        crushchange;
  1565. boolean        nofit;
  1566.  
  1567. /*
  1568. ===============
  1569. =
  1570. = PIT_ChangeSector
  1571. =
  1572. ===============
  1573. */
  1574.  
  1575. boolean PIT_ChangeSector (mobj_t *thing)
  1576. {
  1577.     mobj_t        *mo;
  1578.     
  1579.     if (P_ThingHeightClip (thing))
  1580.         return true;        // keep checking
  1581.  
  1582.     // crunch bodies to giblets
  1583.     if (thing->health <= 0)
  1584.     {
  1585.         //P_SetMobjState (thing, S_GIBS);
  1586.         thing->height = 0;
  1587.         thing->radius = 0;
  1588.         return true;        // keep checking
  1589.     }
  1590.  
  1591.     // crunch dropped items
  1592.     if (thing->flags & MF_DROPPED)
  1593.     {
  1594.         P_RemoveMobj (thing);
  1595.         return true;        // keep checking
  1596.     }
  1597.  
  1598.     if (! (thing->flags & MF_SHOOTABLE) )
  1599.         return true;                // assume it is bloody gibs or something
  1600.         
  1601.     nofit = true;
  1602.     if (crushchange && !(leveltime&3) )
  1603.     {
  1604.         P_DamageMobj(thing,NULL,NULL,10);
  1605.         // spray blood in a random direction
  1606.         mo = P_SpawnMobj (thing->x, thing->y, thing->z + thing->height/2, MT_BLOOD);
  1607.         mo->momx = (P_Random() - P_Random ())<<12;
  1608.         mo->momy = (P_Random() - P_Random ())<<12;
  1609.     }
  1610.         
  1611.     return true;        // keep checking (crush other things)    
  1612. }
  1613.  
  1614. /*
  1615. ===============
  1616. =
  1617. = P_ChangeSector
  1618. =
  1619. ===============
  1620. */
  1621.  
  1622. boolean P_ChangeSector (sector_t *sector, boolean crunch)
  1623. {
  1624.     int            x,y;
  1625.     
  1626.     nofit = false;
  1627.     crushchange = crunch;
  1628.     
  1629. // recheck heights for all things near the moving sector
  1630.  
  1631.     for (x=sector->blockbox[BOXLEFT] ; x<= sector->blockbox[BOXRIGHT] ; x++)
  1632.         for (y=sector->blockbox[BOXBOTTOM];y<= sector->blockbox[BOXTOP] ; y++)
  1633.             P_BlockThingsIterator (x, y, PIT_ChangeSector);
  1634.     
  1635.     
  1636.     return nofit;
  1637. }
  1638.  
  1639.